package com.xsd.prototype.deep;

import java.io.*;

/**
 * @Description:
 * @Author: zhoufuzong
 * @Created: 2021-02-11 11:52:55
 * @Version: 1.1.0
 */
/**
 * 浅拷贝的介绍
 * 1) 对于数据类型是基本数据类型的成员变量，浅拷贝会直接进行值传递，也就是将
 * 该属性值复制一份给新的对象。
 * 2) 对于数据类型是引用数据类型的成员变量，比如说成员变量是某个数组、某个类
 * 的对象等，那么浅拷贝会进行引用传递，也就是只是将该成员变量的引用值（内
 * 存地址）复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个
 * 实例。在这种情况下，在一个对象中修改该成员变量会影响到另一个对象的该成
 * 员变量值
 * 3) 前面我们克隆羊就是浅拷贝
 * 4) 浅拷贝是使用默认的 clone()方法来实现
 * sheep = (Sheep) super.clone();
 */

/**
 * 深拷贝基本介绍
 * 1) 复制对象的所有基本数据类型的成员变量值
 * 2) 为所有引用数据类型的成员变量申请存储空间，并复制每个引用数据类型成员变
 * 量所引用的对象，直到该对象可达的所有对象。也就是说，对象进行深拷贝要对
 * 整个对象进行拷贝
 * 3) 深拷贝实现方式1：重写clone方法来实现深拷贝
 * 4) 深拷贝实现方式2：通过对象序列化实现深拷贝(推荐)
 */

/**
 * 原型模式的注意事项和细节
 * 1) 创建新的对象比较复杂时，可以利用原型模式简化对象的创建过程，同时也能够提
 * 高效率
 * 2) 不用重新初始化对象，而是动态地获得对象运行时的状态
 * 3) 如果原始对象发生变化(增加或者减少属性)，其它克隆对象的也会发生相应的变化，
 * 无需修改代码
 * 4) 在实现深克隆的时候可能需要比较复杂的代码
 * 5) 缺点：需要为每一个类配备一个克隆方法，这对全新的类来说不是很难，但对已有
 * 的类进行改造时，需要修改其源代码，违背了ocp原则，这点请同学们注意.
 */
public class DeepProtoType implements Serializable, Cloneable {

    public String name;

    public DeepCloneTarget deepCloneTarget;

    public DeepProtoType() {
        super();
    }

    // 深拷贝 方式1 使用clone方法

//
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//
//        Object deep =null;
//        // 完成对基本数据类型（属性）和String 的克隆
//        deep = super.clone();
//        // 对引用类型的属性，进行单独处理
//        DeepProtoType deepProtoType = (DeepProtoType) deep;
//        deepProtoType.deepCloneTarget = (DeepCloneTarget) deepCloneTarget.clone();
//
//        return deepProtoType;
//
//    }

    @Override
    public Object clone(){

        // 创建对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos =null;
        ByteArrayInputStream bis  = null;
        ObjectInputStream ois = null;

        try {
            // 序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            // 反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType copyObj = (DeepProtoType)ois.readObject();
            return copyObj;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try{
                if (bos != null) {
                    bos.close();
                }
                if (oos != null) {
                    oos.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (ois != null) {
                    ois.close();
                }
            }catch (Exception e2){

                System.out.println(e2.getMessage());
            }
        }

    }
}
